import 'package:flutter/cupertino.dart';
import 'package:flutter_common_utils/flutter_common_utils.dart';
import 'package:logger/logger.dart';

import 'custom_log_printer.dart';

class LogUtils {
  LogUtils._();

  static Logger logger = setUseDebugPrintOutput();

  ///是否开启日志
  static bool isEnable = true;
  static bool _isInit = false;

  ///日志过滤器
  static bool Function(LogEvent event)? logFilter;

  static final Set<LogCallback> _logCallbacks = {};

  static final Set<OutputCallback> _outputCallbacks = {};

  static void setEnable(bool enable) {
    isEnable = enable;
  }

  // 是否使用print输出
  static Logger setUsePrintOutput() {
    return Logger(
      printer: CustomLogPrinter(),
      filter: CustomLogFilter(),
      output: ConsolePrintOutput(),
    );
  }

  static Logger setUseDebugPrintOutput() {
    return Logger(
      printer: CustomLogPrinter(),
      filter: CustomLogFilter(),
      output: ConsoleDebugOutput(),
    );
  }

  static void runInit() {
    if (_isInit) {
      return;
    }
    _isInit = true;
    // if (AppUtils.isDesktop || AppUtils.isWeb) {
    //   setUsePrintOutput();
    // } else {
    //   setUseDebugPrintOutput();
    // }
    Logger.removeLogListener(_defaultLogListener);
    Logger.addLogListener(_defaultLogListener);
    Logger.removeOutputListener(_defaultOutputListener);
    Logger.addOutputListener(_defaultOutputListener);
  }

  static void _defaultLogListener(LogEvent event) {
    if (_logCallbacks.isEmpty) return;
    final logMsgEvent = LogMsgEvent.fromEvent(event);
    for (var itt in _logCallbacks) {
      itt(logMsgEvent);
    }
  }

  static void _defaultOutputListener(OutputEvent event) {
    if (_outputCallbacks.isEmpty) return;
    final logOutputEvent = LogOutputEvent(LogMsgEvent.fromEvent(event.origin), event.lines, originOutputEvent: event);
    for (var itt in _outputCallbacks) {
      itt(logOutputEvent);
    }
  }

  static void e(
    dynamic msg, {
    Object? error,
    StackTrace? stackTrace,
  }) {
    if (isEnable) {
      final time = DateTime.now();
      // logError("$time $msg");
      logger.e(msg, time: time, error: error, stackTrace: stackTrace);
    }
  }

  static void i(
    dynamic msg, {
    Object? error,
    StackTrace? stackTrace,
  }) {
    if (isEnable) {
      final time = DateTime.now();
      // logInfo("$time $msg");
      logger.i(msg, time: time, error: error, stackTrace: stackTrace);
    }
  }

  static void w(
    dynamic msg, {
    Object? error,
    StackTrace? stackTrace,
  }) {
    if (isEnable) {
      final time = DateTime.now();
      // logWarn("$time $msg");
      logger.w(msg, time: time, error: error, stackTrace: stackTrace);
    }
  }

  static void d(
    dynamic msg, {
    Object? error,
    StackTrace? stackTrace,
  }) {
    if (isEnable) {
      final time = DateTime.now();
      // logDebug("$time $msg");
      logger.d(msg, time: time, error: error, stackTrace: stackTrace);
    }
  }

  //默认打印
  static void print(
    dynamic msg, {
    Object? error,
    StackTrace? stackTrace,
  }) {
    if (isEnable) {
      final time = DateTime.now();
      // logDefault("$time $msg");
      logger.d(msg, time: time, error: error, stackTrace: stackTrace);
    }
  }

  /// 注册一个[LogCallback]，每个新的[LogEvent]都会调用它。
  static void addLogListener(LogCallback callback) {
    _logCallbacks.add(callback);
  }

  /// 删除以前注册的[LogCallback]。
  ///
  ///返回回调是否已成功删除。
  static bool removeLogListener(LogCallback callback) {
    return _logCallbacks.remove(callback);
  }

  /// 注册一个[OutputCallback]，每个新的[OutputEvent]都会调用它。
  static void addOutputListener(OutputCallback callback) {
    _outputCallbacks.add(callback);
  }

  /// 删除以前注册的[OutputCallback]。
  ///
  ///返回回调是否已成功删除。
  static void removeOutputListener(OutputCallback callback) {
    _outputCallbacks.remove(callback);
  }
}

// import '../other/date_utils.dart';
// import 'platform_web_log.dart' if (dart.library.io) 'platform_io_log.dart';
class CustomLogFilter extends LogFilter {
  @override
  bool shouldLog(LogEvent event) {
    if (LogUtils.logFilter?.call(event) == false) {
      return false;
    }
    return true;
  }
}

class LogMsgEvent {
  final LogEvent? origin;

  final LogLevel level;
  final dynamic message;
  final Object? error;
  final StackTrace? stackTrace;

  /// 创建此日志的时间。
  final DateTime time;

  LogMsgEvent(
    this.level,
    this.message, {
    this.origin,
    DateTime? time,
    this.error,
    this.stackTrace,
  }) : time = time ?? DateTime.now();

  @override
  String toString() {
    return 'LogMsgEvent{level: $level, message: $message, error: $error, stackTrace: $stackTrace, time: $time}';
  }

  LogEvent toLogEvent() {
    return LogEvent(LogLevel.fromLogLevel(level), message, time: time, error: error, stackTrace: stackTrace);
  }

  static fromEvent(LogEvent event) {
    return LogMsgEvent(LogLevel.fromLevel(event.level), event.message, time: event.time, error: event.error, stackTrace: event.stackTrace, origin: event);
  }
}

class LogOutputEvent {
  final List<String> lines;
  final LogMsgEvent origin;
  final OutputEvent? originOutputEvent;

  LogLevel get level => origin.level;

  LogOutputEvent(this.origin, this.lines, {this.originOutputEvent});
}

enum LogLevel {
  all(0),
  trace(1000),
  debug(2000),
  info(3000),
  warning(4000),
  error(5000),
  fatal(6000),
  off(10000),
  ;

  final int value;

  const LogLevel(this.value);

  static LogLevel fromLevel(Level level) {
    switch (level) {
      case Level.all:
        return LogLevel.all;
      case Level.verbose:
        return LogLevel.trace;
      case Level.trace:
        return LogLevel.trace;
      case Level.debug:
        return LogLevel.debug;
      case Level.info:
        return LogLevel.info;
      case Level.warning:
        return LogLevel.warning;
      case Level.error:
        return LogLevel.error;
      case Level.wtf:
        return LogLevel.fatal;
      case Level.fatal:
        return LogLevel.fatal;
      case Level.nothing:
        return LogLevel.off;
      case Level.off:
        return LogLevel.off;
    }
  }

  static Level fromLogLevel(LogLevel level) {
    switch (level) {
      case LogLevel.all:
        return Level.all;
      case LogLevel.trace:
        return Level.trace;
      case LogLevel.debug:
        return Level.debug;
      case LogLevel.info:
        return Level.info;
      case LogLevel.warning:
        return Level.warning;
      case LogLevel.error:
        return Level.error;
      case LogLevel.fatal:
        return Level.fatal;
      case LogLevel.off:
        return Level.off;
    }
  }
}

typedef LogCallback = void Function(LogMsgEvent event);

typedef OutputCallback = void Function(LogOutputEvent event);

/// 输出到控制台 使用 debugPrint
/// 相比于 print 1：自动分块输出（默认 ~800 字符/块），2：Release 模式不输出
/// print 可能被截断（Android 约 1024 字符）
class ConsoleDebugOutput extends LogOutput {
  @override
  void output(OutputEvent event) {
    event.lines.forEach(debugPrint);
  }
}

class ConsolePrintOutput extends LogOutput {
  @override
  void output(OutputEvent event) {
    event.lines.forEach(print);
  }
}
// class LogData {
//   final LogLevel level;
//   final Object msg;
//   final DateTime time;
//
//   LogData({required this.level, required this.msg, required this.time});
//
//   @override
//   String toString() {
//     return 'LogData{level: $level, msg: $msg, time: $time}';
//   }
// }
//
// enum LogLevel { ERROR, WARN, INFO, DEBUG, NONE }
